﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MentalAlchemy.Atomics;
using MentalAlchemy.Molecules.Image;
using MentalAlchemy.Molecules.MachineLearning;

namespace MNISTExtractors
{
	public partial class MainForm : Form
	{
		public const string MnistPageName = "MNIST";
		public const string SachinPageName = "Sachin";

		public MainForm()
		{
			InitializeComponent();
		}

		private void SrcBrowseBtn_Click(object sender, EventArgs e)
		{
			var res = folderBrowserDialog1.ShowDialog();
			if (res != DialogResult.OK) return;

			SrcPathBox.Text = folderBrowserDialog1.SelectedPath;
		}

		private void TargetBrowseBtn_Click(object sender, EventArgs e)
		{
			var res = folderBrowserDialog1.ShowDialog();
			if (res != DialogResult.OK) return;

			TargetPathBox.Text = folderBrowserDialog1.SelectedPath;
		}

		private void RunBtn_Click(object sender, EventArgs e)
		{
			var tabName = tabControl.SelectedTab.Text;
			if (tabName == SachinPageName)
			{
				ExtractSachin();
			}
			else if (tabName == MnistPageName)
			{
				ExtractMnist();
			}
		}

		#region - Sachin's collection extraction. -
		private void ExtractSachin()
		{
			var filenameTemplate = "data{0}";
			var dir = TargetPathBox.Text;
			if (dir.Length == 0) { dir = Application.StartupPath; }
			for (int i = 0; i < 10; i++)
			{
				//
				// load source files.
				var file = Path.Combine(SrcPathBox.Text, string.Format(filenameTemplate, i));
				var bmps = ReadFromFile(file);
				//
				// save bitmaps.
				var targetDir = Path.Combine(dir, i.ToString());
				if (!Directory.Exists(targetDir)) { Directory.CreateDirectory(targetDir); }
				SaveImages(targetDir, bmps);
			}
		}

		private static List<Bitmap> ReadFromFile(string filename)
		{
			const int imDim = 28;	// image dimensions.
			const int size = imDim * imDim;	// buffer size for 28x28 images.
			const int imCount = 1000;	// number of images in each file.
			var res = new List<Bitmap>();
			using (var reader = new BinaryReader(File.OpenRead(filename)))
			{
				for (int i = 0; i < imCount; i++)
				{
					var buffer = reader.ReadBytes(size);
					var table = MatrixMath.CreateFromVector(buffer, imDim);
					var bmp = ImageConversion.CreateBmpFromGrayscaleTable(table);
					res.Add(bmp);
				}
			}

			return res;
		} 
		#endregion

		#region - MNIST DB data extraction. -
		public void ExtractMnist ()
		{
			var folder = TrainPathBox.Text;

			List<byte> labelsTrain, labelsTest;
			List<byte[,]> imgTrain, imgTest;
			MNISTExtractor.ExtractEverything(folder, out labelsTrain, out imgTrain, out labelsTest, out imgTest);

			//
			// Save data sorted by labels.
			
			// 0. Create 'Train' and 'Test' subfolders.
			var target = TargetPathBox.Text;
			if (string.IsNullOrEmpty(target)) { target = Application.StartupPath; }
			var trainFolder = Path.Combine(target, "Train");
			var testFolder = Path.Combine(target, "Test");

			if (!Directory.Exists(trainFolder)){ Directory.CreateDirectory(trainFolder); }
			if (!Directory.Exists(testFolder)) { Directory.CreateDirectory(testFolder); }
			for (int i = 0; i < 10; i++)
			{
				var numDir = Path.Combine(trainFolder, i.ToString());
				if (!Directory.Exists(numDir)) { Directory.CreateDirectory(numDir); }
			}
			for (int i = 0; i < 10; i++)
			{
				var numDir = Path.Combine(testFolder, i.ToString());
				if (!Directory.Exists(numDir)) { Directory.CreateDirectory(numDir); }
			}

			// save train images.
			var trainImg = new List<Bitmap>[10];
			for (int i = 0; i < 10; i++) { trainImg[i] = new List<Bitmap>(); }
			for (int j = 0; j < labelsTrain.Count; j++)
			{
				var idx = labelsTrain[j];
				trainImg[idx].Add(ImageConversion.CreateBmpFromGrayscaleTable(imgTrain[j]));
			}
			for (int i = 0; i < 10; i++)
			{
				var dir = Path.Combine(trainFolder, i.ToString());
				SaveImages(dir, trainImg[i]);
			}

			// save test images.
			var testImg = new List<Bitmap>[10];
			for (int i = 0; i < 10; i++) {testImg[i] = new List<Bitmap>();}
			for (int j = 0; j < labelsTest.Count; j++)
			{
				var idx = labelsTest[j];
				testImg[idx].Add(ImageConversion.CreateBmpFromGrayscaleTable(imgTest[j]));
			}
			for (int i = 0; i < 10; i++)
			{
				var dir = Path.Combine(testFolder, i.ToString());
				SaveImages(dir, testImg[i]);
			}
		}
		#endregion

		private static void SaveImages (string dir, List<Bitmap> bmps)
		{
			for (int i = 0; i < bmps.Count; i++)
			{
				var file = string.Format("{0}.bmp", i);
				bmps[i].Save(Path.Combine(dir, file), ImageFormat.Bmp);
			}
		}

		private void TrainBrowseBtn_Click(object sender, EventArgs e)
		{
			var res = folderBrowserDialog1.ShowDialog();
			if (res != DialogResult.OK) return;

			TrainPathBox.Text = folderBrowserDialog1.SelectedPath;
		}
	}
}
